#ifndef DIE_H
#define DIE_H

#include <ed_core/global/defs.h>

#include <QtCore/QList>

namespace ed_core
{

/**
 * @brief The Die class describes a Die with an arbitrary number of faces (RdJ p.17)
 * @see Die::roll()
 */
class ED_CORE_API Die
{
public:
  /**
   * @brief Default constructor
   * @param faces The number of faces this die has (Generally 4, 6, 8, 10, 12 or 20)
   */
  Die(quint32 faces=0);

  /**
   * @brief Copy constructor
   */
  Die(const ed_core::Die& other);

  virtual ~Die();
  bool operator==(const ed_core::Die& other) const;
  Die& operator=(const ed_core::Die& other);

  /**
   * @return the number of faces this die has.
   */
  quint32 faces() const;

  /**
   * @return true if this die is valid (i.e has 1 face or more)
   */
  bool isValid() const;

  /**
   * @brief The roll method returns a roll result for this die based on the Action Test rules (RdJ p.17)
   * @note The bonus die is automatically rolled and added to the result when the die has yielded the maximum possible result.
   */
  quint32 roll() const;

private:
  static quint32 roll(quint32 faces);
  quint32 _faces;
};

/**
 * @brief The DicePool class groups a number of dice that are rolled together based on the Action Test rules (RdJ p.18)
 * The DicePool can have a base modifier (see DicePool::DicePool(qint32)) and each roll (see DicePool::roll(modifier)) can take a separate modifier of its own.
 */
class ED_CORE_API DicePool
{
public:
  /**
   * @brief Copy constuctor
   * @note The base modifier from other is added to the current base modifier.
   */
  DicePool(const ed_core::DicePool& other);

  /**
   * @brief Construct an empty DicePool with a given base modifier.
   * @param baseModifier A modifier that will be applied to all tests and added to each test's specific modifier.
   */
  DicePool(qint32 baseModifier=0);

  virtual ~DicePool();

  /**
   * @brief Copy operator
   * @see DicePool::DicePool(const DicePool&)
   */
 ed_core::DicePool& operator=(const ed_core::DicePool& other);

  /**
   * @brief Add a die into the pool
   * @param d The die to be added
   */
  ed_core::DicePool& operator<<(const ed_core::Die& d);

  /**
   * @brief Merges p with the current pool. The base modifiers from p is added to this.
   * @param p The pool to merge
   */
  ed_core::DicePool& operator<<(const ed_core::DicePool& p);

  /**
   * @brief Rolls each die from the pool, taking into account the base modifier and the roll's modifier.
   * This method is based over the Action Tests rules (RdJ p.18).
   * @param modifier A modifier that is local only to the current roll.
   * @return The test's result.
   */
  quint32 roll(qint32 modifier=0);

private:
  QList<ed_core::Die> _pool;
  qint32 _baseModifier;
};

// Those macro definitions are helpers for quick Die object construction
#define D4  ed_core::Die(4)
// The D4-1/D4-2 die has a -1/-2 modifier applied once all other bonus dice have been rolled (RdJ p.17)
#define D4_1 (ed_core::DicePool(-1) << D4)
#define D4_2 (ed_core::DicePool(-2) << D4)
#define D6  ed_core::Die(6)
#define D8  ed_core::Die(8)
#define D10 ed_core::Die(10)
#define D12 ed_core::Die(12)
#define D20 ed_core::Die(20)

} // namespace ed_core

#endif // DIE_H
